package CTRLayer;
import ModelLayer.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Date;

/**
 * This class controls the creation of orders, updates the stock and the customer's account balance.
 * 
 * @author Gruppe 4 
 * @version 4. juni 2012
 */
public class OrderCTR
{
    // instance variables
    private OrderCollection orders;
    private PersonCTR personCTR;
    private ProductCTR productCTR;
    
    /**
     * The constructor of the class initializes: orders, personCTR and productCTR.
     */
    public OrderCTR()
    {
        orders = OrderCollection.getInstance();
        personCTR = new PersonCTR();
        productCTR = new ProductCTR();
    }
    
    /**
     * Create a new order. 
     * The date is generated by the Date class in Java.
     * 
     * @param orderNo orderNo a unique order number 
     * 
     * @return none
     */
    public void createOrder(int OrderNo) 
    {
        int inputStatus = 0;
        Date date = new Date();
        Order order = new Order(OrderNo, inputStatus, date);
        orders.addOrder(OrderNo, order);
    }

    /**
     * Add a customer to the order.
     * 
     * @param phoneNo phoneNo a number used to find the customer who is to be added to the order
     * @param orderNo orderNo a number used to find the order
     * 
     * @return none
     */
    public void addCustomer(String phoneNo, int orderNo)
    {        
        Customer customer = (Customer) personCTR.findPerson(phoneNo);               
        Order order = orders.findOrder(orderNo);                                    
        order.addCustomer(customer);                // just add one time            
    }
    
    /**
     * Add a salesman to the order.
     * 
     * @param phoneNo phoneNo a number used to find the salesman who is to be added to the order
     * @param orderNo orderNo a number used to find the order
     * 
     * @return none
     */
    public void addSalesman(String phoneNo, int orderNo)
    {        
        Salesman salesman = (Salesman) personCTR.findPerson(phoneNo);                 
        Order order = orders.findOrder(orderNo);                                     
        order.addSalesman(salesman);                              
    }
    
    /**
     * Add a product to the order.
     * 
     * @param barcode barcode a number used to find the product that is to be added to the order
     * @param quantity quantity is the amount of products of the same type
     * @param discount discount is how big a discount the customer gets on the product
     * @param orderNo orderNo a number used to find the order
     * @param ignore ignore used to control what parts of the code that should be executed
     * 
     * @return quantityResult used in the UI layer to inform the user that the storage capacity is exceeded
     */
    public int addProduct(int barcode, int quantity, int discount, int orderNo, int ignore) 
    {
        Product product = productCTR.findProduct(barcode);                            
        int quantityResult = 0;
        int CompositeDone = 0;
        int missingProducts = 0;
        int newMissingProducts = 0;
        
        // ArrayList that contains numbers telling how many subproducts are missing of each type. 
        ArrayList<Integer> missingProductsComposite = new ArrayList<Integer>();
        
        if (ignore == 0 && product instanceof NonCompositeProduct) {
            // Find out if there are enough products.
            quantityResult = calculateQuantity(product, quantity);
        } else if (product instanceof CompositeProduct) { // Happens no matter what value ignore has.
                                                          // Because the Array needs the values.
            CompositeProduct compositeProduct = (CompositeProduct) product;
            
            // Find out if there are enough products of each subproduct.
            for(Partlist partlist : compositeProduct.getChildren()) {
                quantityResult = calculateQuantity(partlist.getProduct(), quantity);
                missingProducts = partlist.getProduct().getQuantity() - (partlist.getQuanitity() * quantity);
               
                if (partlist.getProduct().getQuantity() > 0 && missingProducts < 0) {
                    // If products are missing: Add the number to missingProductsComposite.
                    newMissingProducts = -missingProducts;
                    missingProductsComposite.add(newMissingProducts);
                } else if (partlist.getProduct().getQuantity() <= 0) {
                    // If the quantity is below 0, add the needed amount of product to missingProductsComposite.
                    missingProductsComposite.add(partlist.getQuanitity() * quantity);
                } else {
                    // If there are enough products add 0 missing products to missingProductsComposite.
                    missingProductsComposite.add(0);
                }
                // Updates the quantity of each subproduct
                /** !!!!!!!!!!AFR skal tjekke op på følgende linje kode!!!!!!!!!!!!!! */
                /** Brug måske følgende tjek: if (quantityResult == 0 || ignore == 1) { */
                partlist.getProduct().setQuantity(missingProducts);
            }
        }
        
        // After the quantities has been calculated and the user has had a chance to respond
        // to the low quantity this method is called again (in the UIlayer).
        // Or if quantityResult is = 0 (which means that quantity is still over the minimum).
        // This part of the code is to be executed.
        if (quantityResult == 0 || ignore == 1) {
            missingProducts = product.getQuantity() - quantity;
            SubOrder subOrder = new SubOrder(product, quantity);
            
            // ArrayList in subOrder get values from missingProductsComposite.
            subOrder.setMissingProductsComposite(missingProductsComposite);
            subOrder.setDiscount(discount);
            
            // If ignore = 1: missingProducts are updated for main products.
            if (ignore == 1) {
                if (product.getQuantity() > 0) {
                    newMissingProducts = -missingProducts;
                    subOrder.setMissingProducts(newMissingProducts);
                } else if (product.getQuantity() <= 0) {
                    subOrder.setMissingProducts(quantity);
                }
            }
            
            product.setQuantity(missingProducts);
            
            // A suborder is added to an order.
            Order order = orders.findOrder(orderNo);                                      
            order.addSubOrder(subOrder);
        }
        return quantityResult;
    }
    
    /**
     * Control what quantity is compared to min-capacity and 0. 
     * 
     * @param product product needed to get quantity
     * @param quantity quantity is the quantity needed on the order
     * 
     * @return int used to inform user about the conditions and in control structures
     */
    public int calculateQuantity(Product product, int quantity)
    {
        NonCompositeProduct nonCompositeProduct = (NonCompositeProduct) product;
        int result = product.getQuantity() - quantity;
        if(result < 0) {
            return 1; 
        } else if (result < nonCompositeProduct.getMinCapacity()) {
            return 2;
        } else {
            return 0;
        }
    }
    
    /**
     * Calculate total price without any discount.
     * 
     * @param orderNo orderNo needed to find the order.
     * 
     * @return none
     */
    public void calculateTotalPrice(int orderNo) {
        Order order = orders.findOrder(orderNo);
        ArrayList<SubOrder> subOrders = order.getSubOrders();
        double totalPrice = 0.0;
        double productPrice = 0.0;
        double price = 0.0;
        
        for (SubOrder subOrder : subOrders) {
            if (subOrder.getProduct().getOfferPrice() != 0.0) 
                price = subOrder.getProduct().getOfferPrice();
            else
                price = subOrder.getProduct().getPrice();
            productPrice = price * subOrder.getQuantity();
            totalPrice += productPrice;
        }
        
        order.setTotalPrice(totalPrice);
    }
    
    /**
     * Calculate price with 20% discount
     * 
     * @param orderNo orderNo needed to find the order.
     * 
     * @return none
     */
    public void calculateMaxDiscount(int orderNo) {
        Order order = orders.findOrder(orderNo);
        double maxDiscount = order.getTotalPrice() * 0.80;
        order.setDiscountPrice(maxDiscount);
    }
    
        
    /**
     * Compare max discount to the discount given on the different products
     * and the customer discount together.
     * 
     * @param orderNo orderNo needed to find the order
     * 
     * @return compareDiscounts lets the user know if the discount has been regulated
     */
    public boolean compareDiscounts(int orderNo) {
        Order order = orders.findOrder(orderNo);
        ArrayList<SubOrder> subOrders = order.getSubOrders();
        double totalPrice = 0.0;
        double productPrice = 0.0;
        double discount = 0.0;
        double price = 0.0;
        
        for (SubOrder subOrder : subOrders) {
            if (subOrder.getProduct().getOfferPrice() != 0.0) 
                price = subOrder.getProduct().getOfferPrice();
            else
                price = subOrder.getProduct().getPrice();
            productPrice = price * subOrder.getQuantity();
            
            if (subOrder.getDiscount() != 0)
                discount = productPrice * ((double) subOrder.getDiscount() / 100);
            else
                discount = 0.0;
                
            productPrice = productPrice - discount;
            totalPrice += productPrice;
        }
        
        totalPrice = customerDiscount(orderNo, totalPrice);
        
        // Inform the user if the discount has to be regulated down.
        if (totalPrice > order.getDiscountPrice()) {
            order.setDiscountPrice(totalPrice);
            return false;
        } else {
            return true;
        }

    }
    
    /**
     * Compare max discount to the discount given on the different products
     * and the customer discount together.
     * 
     * @param orderNo orderNo needed to find the order
     * 
     * @return compareDiscounts lets the user know if the discount has been regulated
     */
    public double customerDiscount(int orderNo, double totalPrice)
    {
        Order order = orders.findOrder(orderNo);
        
        if (order.getCustomer().getCustomerType().equals("Haandvaerker")) {
            return totalPrice * 0.95;
        } else {
            return totalPrice;
        }
    }
    
    /**
     * Update the customers account by subtracting discountPrice
     * 
     * @param orderNo orderNo needed to find the order
     * 
     * @return none
     */
    public void setCustomerAccount(int orderNo)
    {
        Order order = orders.findOrder(orderNo);
        order.getCustomer().setAccountBalance(order.getCustomer().getAccountBalance() - order.getDiscountPrice());
    }
    
    /**
     * If the salesman chooses to add more products, this method is called.
     * 
     * @param barcode barcode to find the product
     * @param quantity quantity the amount of products that the salesman wants to order.
     * 
     * @return product.getQuantity() to show the salesman what the updated amount is.
     */
    public int updateQuantity(int barcode, int quantity)
    {
        Product product = productCTR.findProduct(barcode);
        int productQuantity = product.getQuantity();
        product.setQuantity(productQuantity + quantity);
        return product.getQuantity();
    }
    
    /**
     * Find an order.
     * 
     * @param orderNo orderNo to find the order
     * 
     * @return order as Order
     */
    public Order findOrder(int orderNo) 
    {
        return orders.findOrder(orderNo);
    }
    
    /**
     * Edit the status of an order.
     * 
     * @param orderNo orderNo to find the order
     * @param choice choice to tell what status the user choose
     * 
     * @return none
     */
    public void setStatus(int orderNo, int choice)
    {
        Order order = findOrder(orderNo);
        order.setStatus(choice);
    }
    
    /**
     * Get all orders, used for printing a list.
     * 
     * @param none
     * 
     * @return orders as HashMap
     */
    public HashMap<Integer, Order> ListAllOrders()
    {
        return orders.ListAllOrders();    
    }
}